﻿using System;
using System.Collections;
using System.Collections.Generic;

/*
 * 2014-9-22
 *  链式队列最重要的是知道头和尾节点
 *  完成非泛型的链式队列版本，对他又有了新的了解
 *  
 * 2014-9-23
 *  完成泛型的链式队列
 */

namespace Ycg.Core
{
    public class LinkQueue : IEnumerable
    {
        private LinkNode _headNode;
        private LinkNode _tailNode;

        public LinkQueue()
        {
        }

        public object Dequeue()
        {
            if (this._headNode == null)
            {
                throw new Exception("The node is null.");
            }
            object data = this._headNode.Data;
            this._headNode = this._headNode.NextNode;
            return data;
        }

        public void Enqueue(object data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (this._headNode == null)
            {
                this._headNode = new LinkNode(data);
                this._tailNode = this._headNode;
            }
            else
            {
                //这边很重要
                //1.首先先把上一个节点中下一个节点地址给赋值
                //2.然后再把最后节点赋值，也就是上面的下一个节点
                this._tailNode.NextNode = new LinkNode(data);
                this._tailNode = this._tailNode.NextNode;
            }
        }

        public IEnumerator GetEnumerator()
        {
            return new Enumerator(this._headNode);
        }

        private class Enumerator : IEnumerator
        {
            private LinkNode _headNode;

            public Enumerator(LinkNode headNode)
            {
                this._headNode = headNode;
            }

            public object Current
            {
                get
                {
                    object data = this._headNode.Data;
                    this._headNode = this._headNode.NextNode;
                    return data;
                }
            }

            public bool MoveNext()
            {
                return this._headNode != null;
            }

            public void Reset()
            {
                throw new NotImplementedException();
            }
        }
    }

    public class LinkQueue<T> : IEnumerable<T>
    {
        private LinkNode<T> _headNode;
        private LinkNode<T> _tailNode;

        public LinkQueue()
        {
        }

        public T Dequeue()
        {
            if (this._headNode == null)
            {
                throw new Exception("No data.");
            }
            T data = this._headNode.Data;
            this._headNode = this._headNode.NextNode;
            return data;
        }

        public void Enqueue(T data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (this._headNode == null)
            {
                this._headNode = new LinkNode<T>(data);
                this._tailNode = this._headNode;
            }
            else
            {
                this._tailNode.NextNode = new LinkNode<T>(data);
                this._tailNode = this._tailNode.NextNode;
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return new Enumerator(this._headNode);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this._headNode);
        }

        private class Enumerator : IEnumerator<T>
        {
            private LinkNode<T> _headNode;

            public Enumerator(LinkNode<T> headNode)
            {
                this._headNode = headNode;
            }

            public T Current
            {
                get
                {
                    T data = this._headNode.Data;
                    this._headNode = this._headNode.NextNode;
                    return data;
                }
            }

            public void Dispose()
            {

            }

            object IEnumerator.Current
            {
                get { throw new NotImplementedException(); }
            }

            public bool MoveNext()
            {
                return this._headNode != null;
            }

            public void Reset()
            {
                throw new NotImplementedException();
            }
        }
    }
}